package com.jayanslow.lighting.server.dmx;
import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.TooManyListenersException;

@SuppressWarnings("restriction")
public class SerialConnection implements SerialPortEventListener {
	Serial serial;
	public SerialConnection(Serial s) {
		super();
		serial = s;
	}
	
	SerialPort serialPort;
        /** The port we're normally going to use. */
	private static final String PORT_NAMES[] = { 
			"/dev/tty.usbmodemfa131", // Mac OS X
			"/dev/ttyUSB0", // Linux
			"COM3", // Windows
			};
	/** Buffered input stream from the port */
	private InputStream input;
	/** The output stream to the port */
	private OutputStream output;
	/** Milliseconds to block while waiting for port open */
	private static final int TIME_OUT = 2000;
	/** Default bits per second for COM port. */
	private static final int DATA_RATE = 9600;

	public void initialize() throws SerialException {
		CommPortIdentifier portId = null;
		@SuppressWarnings("rawtypes")
		Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();
		// iterate through, looking for the port
		while (portEnum.hasMoreElements()) {
			CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();
			for (String portName : PORT_NAMES) {
				if (currPortId.getName().equals(portName)) {
					portId = currPortId;
					break;
				}
			}
		}

		if (portId == null) throw new SerialException("Unable to find port");

		try {
			// open serial port, and use class name for the appName.
			serialPort = (SerialPort) portId.open(this.getClass().getName(),
					TIME_OUT);

			// set port parameters
			serialPort.setSerialPortParams(DATA_RATE,
					SerialPort.DATABITS_8,
					SerialPort.STOPBITS_1,
					SerialPort.PARITY_NONE);

			// open the streams
			input = serialPort.getInputStream();
			output = serialPort.getOutputStream();

			// add event listeners
			serialPort.addEventListener(this);
			serialPort.notifyOnDataAvailable(true);
		} catch (PortInUseException e) {
			throw new SerialException("Port in Use");
		} catch (UnsupportedCommOperationException e) {
			throw new SerialException("Unable to connect to device (UnsupportedCommOperationException : " + e.getMessage() + ")");
		} catch (IOException e) {
			throw new SerialException("Unable to connect to device (IOException : " + e.getMessage() + ")");
		} catch (TooManyListenersException e) {
			throw new SerialException("Unable to connect to device (TooManyListenersException : " + e.getMessage() + ")");
		}
	}
	
	public synchronized void send(byte[] bs) throws SerialException {
		if (serialPort == null) initialize();
		try {
			output.write(bs);
		} catch (IOException e) {
			throw new SerialException("Unable to send data (IOException : " + e.getMessage() + ")");
		}
	}
	public synchronized void send(String s) throws SerialException {
		
		char[] cs = s.toCharArray();
		byte[] bs = new byte[cs.length];
		for (int i = 0; i < cs.length; i++) bs[i] = (byte) cs[i];
		send(bs);
	}

	//Closes connection
	public synchronized void close() {
		if (serialPort != null) {
			serialPort.removeEventListener();
			serialPort.close();
		}
	}

	//Recieves data from device
	public synchronized void serialEvent(SerialPortEvent oEvent) {
		if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
			try {
				int available = input.available();
				byte chunk[] = new byte[available];
				input.read(chunk, 0, available);
				//System.out.print(new String(chunk));
				//TODO send data to Serial.java
			} catch (Exception e) {	}
		}
	}

	public boolean isConnected() {
		return serialPort != null;
	}
}